Для программирования расширенных хранимых процедур
Microsoft предоставляет ODS (Open Data Service) API – набор макросов и
функций, используемых для построения серверных приложений позволяющих
расширить функциональность MS SQL Server 2000.
Расширенные
хранимые процедуры - это обычные функции написанные на С/C++ с применением
ODS API и WIN32 API, оформленные в виде библиотеки динамической компоновки
(dll) и призванные, как я уже говорил, расширять функциональность SQL
сервера. ODS API предоставляет разработчику богатый набор функций
позволяющих передавать данные клиенту, полученные от любых внешних
источников данных (data source) в виде обычных наборов записей (record
set). Так же, extended stored procedure может возвращать значения через
переданный ей параметр (OUTPUT parametr).
Как работают
расширенные хранимые процедуры.1. Когда клиентское приложение
вызывает расширенную хранимую процедуру, запрос передаётся в TDS формате
через сетевую библиотеку Net-Libraries и Open Data Service ядру MS SQL
SERVER.
2. SQL Sever находит dll – библиотеку ассоциированную с именем
расширенной хранимой процедуры и загружает её в свой контекст, если она не
была загружена туда ранее, и
вызывает расширенную хранимую процедуру,
реализованную как функцию внутри dll.
3. Расширенная хранимая процедура
выполняет на сервере необходимые ей действия и передаёт набор результатов
клиентскому приложению, используя сервис предоставляемый ODS
API.
Особенности расширенных хранимых процедур.-
Расширенные хранимые процедуры - это функции выполняющиеся в адресном
пространстве MS SQL Server и в контексте безопасности учётной записи под
которой запущена служба MS SQL Server;
- После того, как dll библиотека
с расширенными хранимыми процедурами была загружена в память, она остаётся
там до тех пор, пока SQL Server не будет остановлен, или пока
администратор не выгрузит её принудительно, используя команду :
DBCC
DLL_name (FREE).- Расширенная хранимая процедура запускается на
выполнение так же, как и обычная хранимая процедура:
EXECUTE
xp_extendedProcName @param1, @param2 OUTPUT@param1 – входной
параметр
@param2 – входной/выходной
параметр
Внимание!Так как расширенные хранимые
процедуры выполняются в адресном пространстве процесса службы MS SQL
Server, любые критические ошибки, возникающие в их работе, могут вывести
из строя ядро сервера, поэтому рекомендуется тщательно протестировать Вашу
DLL перед установкой на рабочий сервер.
Создание расширенных
хранимых процедур.Расширенная хранимая процедура – эта функция
имеющая следующий прототип:
SRVRETCODE xp_extendedProcName
(SRVPROC * pSrvProc);Параметр
pSrvProc – указатель на
SRVPROC структуру, которая является описателем (handle) каждого
конкретного клиентского подключения. Поля этой структуры
недокументированны и содеражат информацию, которую библиотека ODS
использует для управления коммуникацией и данными между серверным
приложением (Open Data Services server application) и клиентом. В любом
случае, Вам не потребуется обращаться к этой структуре и тем более нельзя
модифицоравать её. Этот параметр требуется указывать при вызове любой
функции ODS API, поэтому в дальнейшем я небуду останавливаться на его
описании.
Использование префикса xp_ необязательно, однако существует
соглашение начинать имя расширенной хранимой процедуры именно так, чтобы
подчеркнуть отличие от обычной хранимой процедуры, имена которых, как Вы
знаете, принято начинать с префикса sp_.
Так же следует помнить, что
имена расширенных хранимых процедур чувствительны к регистру. Не забывайте
об этом, когда будете вызвать расширенную хранимую процедуру, иначе вместо
ожидаемого результата, Вы получите сообщение об ошибке.
Если Вам
необходимо написать код инициализации/деинициализации dll, используйте для
этого стандартную функцию DllMain(). Если у Вас нет такой необходимости, и
вы не хотите писать DLLMain(), то компилятор соберёт свою версию функции
DLLMain(), которая ничего не делает, а просто возвращает TRUE. Все
функции, вызываемые из dll (т.е. расширенные хранимые процедуры) должны
быть объявлены, как экспортируемые. Если Вы пишете на MS Visual C++
используйте директиву
__declspec(dllexport). Если Ваш компилятор не
поддерживает эту директиву, опишите экспортируемую функцию в секции
EXPORTS в DEF файле.
Итак, для создания проекта, нам понадобятся
следующие файлы:
- Srv.h – заголовочный файл, содержит описание
функций и макросов ODS API;
- Opends60.lib – файл импорта библиотеки
Opends60.dll, которая и реализует весь сервис предоставляемый ODS
API.
Microsoft настоятельно рекомендует, чтобы все DLL библиотеки
реализующие расширенные хранимые процедуры экспортировали
функцию:
__declspec(dllexport) ULONG
__GetXpVersion()
{
return ODS_VERSION;
}
Когда MS SQL
Server загружает DLL c extended stored procedure, он первым делом вызывает
эту функцию, чтобы получить информацию о версии используемой библиотеки.
Для написания своей первой extended stored procedure, Вам
понадобится установить на свой компьютер:
- MS SQL Server 2000
любой редакции (у меня стоит Personal Edition). В процесе инсталляции
обязательно выберите опцию source sample
- MS Visual C++ (я использовал
версию 7.0 ), но точно знаю подойдёт и 6.0
Установка SQL Server -a
нужна для тестирования и отладки Вашей DLL. Возможна и отладка по сети, но
я этого никогда не делал, и поэтому установил всё на свой локальный диск.
В поставку Microsoft Visual C++ 7.0 редакции Interprise Edition входит
мастер – Extended Stored Procedure DLL Wizard. В принципе, ничего сверх
естественного он не делает, а только генерирует заготовку – шаблон
расширенной хранимой процедуры. Если Вам нравятся мастера, можете
использовать его. Я же предпочитаю делать всё ручками, и поэтому не буду
рассматривать этот случай.
Теперь к делу:
- Запустите Visual C++
и создайте новый проект - Win32 Dynamic Link Library.
- Включите в
проект заголовочный файл - #include
;
- Зайдите в меню Tools
=> Options и добавьте пути поиска include и library файлов. Если , при
установке MS SQL Server, Вы ничего не меняли, то задайте:
-
C:Program FilesMicrosoft SQL Server80ToolsDevToolsInclude для заголовочных
файлов;
- C:Program FilesMicrosoft SQL Server80ToolsDevToolsLib для
библиотечных файлов.
- Укажите имя библиотечного файла opends60.lib в
опциях линкера.
На этом подготовительный этап закончен, можно
приступать к написанию своей первой extended stored
procedure.
Постановка задачи.
Прежде чем приступать к
программированию, необходимо чётко представлять с чего начать, какой
должен быть конечный результат, и каким способом его добиться. Итак, вот
нам техническое задание:
« Разработать расширенную хранимую
процедуру для MS SQL Server 2000, которая получает полный список
пользователей зарегистрированных в домене, и возвращает его клиенту в виде
стандартного набора записей (record set). В качестве первого входного
параметра функция получает имя сервера содержащего базу данных каталога
(Active Directory), т.е имя контролера домена. Если этот параметр равен
NULL, тогда необходимо передать клиенту список локальных групп. Второй
параметр будет использоваться extended stored procedure для возварата
значения – результата успешной/неуспешной работы (OUTPUT параметр). Если,
расширенная хранимая процедура выполнена успешно, тогда необходимо
передать количество записей возвращённых в клиентский record set , если в
процессе работы не удалось получить требуемую информацию, значение второго
параметра необходимо установить в -1, как признак неуспешного завершения.
»
«Условный прототип» расширенной хранимой процедуры
следующий:
xp_GetUserList(@NameServer varchar[15], @CountRec int
OUTPUT);
А вот шаблон расширенной хранимой процедуры, который нам
предстоит наполнить содержанием:
#include
#include
#define XP_NOERROR 0
#define XP_ERROR
-1
__declspec(dllexport) SERVRETCODE xp_GetGroupList(SRVPROC*
pSrvProc)
{
//Проверка кол-ва переданных
параметров
…
//Проверка типа переданных
параметров
…
//Проверка, является ли параметр 2 OUTPUT
параметром
…
//Проверка, имеет ли параметр 2 достаточную длину для
сохранения значения
…
//Получение входных
параметров
…
//Получение списка пользователей
…
// Посылка
полученных данных клиенту в виде стандартного набора записей (record
set)
…
//Установка значения OUTPUT параметра
…
return
(XP_NOERROR);
}
Работа с входными
параметрами
В этой главе я не хочу рассеивать Ваше внимание на
посторонних вещах, а хочу сосредоточить его на работе с переданными в
расширенную хранимую процедуру параметрами. Поэтуму мы несколько упростим
наше техническое задание и разработаем тольку ту его часть, которая
работает с входными параметрами. Но сначал не много теории …
Первое действие, которое должна выполнить наша exteneded stored
procedure , - получить параметры, которые были переданы ей при вызове.
Следуя приведённому выше алгоритму нам необходимо выполнить следующие
действия:
- Определить кол-во переданных параметров;
- Убедится,
что переданные параметры имеют верный тип данных;
- Убедиться, что
указанный OUTPUT параметр имеет достаточную длину, для сохранения в нём
значения возвращаемого нашей extended stored procedure.
- Получить
переданные параметры;
- Установить значения выходного параметра как
результат успешного/неуспешного завершения работы extended stored
procedure .
Теперь рассмотрим подробно каждый
пункт:
Определение количества переданных в расширенную хранимую
процедуру параметров
Для получения количества переданных
параметров необходимо использовать функцию:
int srv_rpcparams (
SRV_PROC * srvproc );
При успешном завершении функция
возвращает количество переданных в расширенную хранимую процедуру
параметров. Если extended stored procedure была вызвана без параметров -
srv_rpcparams ввернёт -1. Параметры могут быть переданы по имени или по
позиции (unnamed). В любом случае, нельзя смешивать эти два способа.
Попытка передачи в функцию входных параметров по имени и по позиции
одновременно - приведёт к возникновению ошибки, и srv_rpcparams вернёт 0
.
Определение типа данных и длины переданых параметров
Для
получения информации о типе и длине переданных параметров Microsoft
рекомендует использовать функцию srv_paramifo. Эта универсальная функция
заменяет вызовы srv_paramtype, srv_paramlen, srv_parammaxlen, которые
теперь считаются устаревшими. Вот её прототип:
int srv_paraminfo
(
SRV_PROC * srvproc,
int n,
BYTE * pbType,
ULONG*
pcbMaxLen,
ULONG * pcbActualLen,
BYTE * pbData,
BOOL * pfNull
);
pByte – указатель на переменную получающую информацию о
типе входного параметра;
pbType – задаёт порядковый номер
параметра. Номер первого параметра начинается с 1.
pcbMaxLen –
указатель на переменную, в которую функция заносит максимальное значение
длины параметра. Это значение обусловлено конкретным типом данных
переданного параметра, его мы и будем использовать, чтобы убедиться втом,
что OUTPUT параметр имеет достаточную длину для сохранения передаваемых
данных.
pcbActualLen – указатель на реальную длину параметра
переданного в расширенную хранимую процедуру при вызове. Если передаваемый
параметр имеет нулевую длину, а флаг pfNull устанавлен в FALSE то (*
pcbActualLen) ==0.
pbData - указатель на буфер, память для
которого должна быть выделена перед вызовом srv_paraminfo. В этом буфере
функция размещает полученные от extended stored procedure входные
параметры. Размер буфера в байтах равен значению pcbMaxLen. Если этот
параметр установлен в NULL, данные в буфер не записываются, но функция
корректно возвращает значения *pbType, *pcbMaxLen, *pcbActualLen, *pfNull.
Поэтому вызывать srv_paraminfo нужно дважды: сначала с pbData=NULL, потом,
выделив необходимый размер памяти под буфер равный pcbActualLen, вызвать
srv_paraminfo второй раз, передав в pbData указатель на выделенный блок
памяти.
pfNull – указатель на NULL-флаг. srv_paraminfo
устанавливает его в TRUE, если значение входного параметра равно
NULL.
Проверка, является ли второй параметр OUTPUT
параметром.
Функция srv_paramstatus() предназначена для
определения статуса переданного параметра:
int srv_paramstatus
(
SRV_PROC * srvproc,
int n
);
n – номер параметра
переданного в расширенную хранимую процедуру при вызове. Напомню:
параметры всегда нумеруются с 1.
Для возврата значения, srv_paramstatus
использует нулевой бит. Если он установлен в 1 – переданный параметр
является OUTPUT параметром, если в 0 – обычным параметром, переданным по
значению. Если, exteneded stored procedure была вызвана без параметров,
функция вернёт -1.
Установка значения выходного
параметра.
Выходному параметру, переданному в расширеную хранимую
можно передать значение используя функцию srv_paramsetoutput. Эта новая
функция заменяет вызов функции srv_paramset, которая теперь считается
устаревашай, т.к. не поддерживает новые типы данных введённые в ODS API и
данные нулевой длины.
int srv_paramsetoutput (
SRV_PROC * srvproc,
int n,
BYTE * pbData,
ULONG cbLen,
BOOL fNull
);
n – порядковый номер параметра, которому будет
присвоено новое значение. Это должен быть OUTPUT
параметр.
pbData – указатель на буфер с данными, которые будут
посланы клиенту для установки значения выходного
параметра.
cbLen – длина буфера посылаемых данных. Если тип
данных переданного OUTPUT параметра определяет данные постоянной длины и
не разрешает хранение значения NULL (например SRVBIT или SRVINT1), то
функция игнорирует параметр cbLen. Значение cbLen=0 указывает на данные
нулевой длины, при этом парметр fNull должен быть установлен в
FALSE.
fNull – установите этот его в TRUE, если возвращаемому
параметру необходимо присвоить значение NULL, при этом значение cbLen
должно быть равно 0, иначе функция завершится с ошибкой. Во всех остальных
случаях fNull=FALSE.
В случае успешного завершения функция возвращает
SUCCEED. Если возвращаемое значение равно FAIL, значит вызов был
неудачным. Всё просто и понятно …
Теперь мы достаточно знаем, для того
чтобы написать свою первую расширенную хранимую процедуру, которая будет
возвращать значение через переданный ей параметр.Пусть, по сложившейся
традиции, это будет строка – «Hello world!» Отладочну версию примера можно
скачать здесь.
#include
#define XP_NOERROR
0
#define XP_ERROR 1
#define MAX_SERVER_ERROR 20000
#define
XP_HELLO_ERROR MAX_SERVER_ERROR+1
void printError (SRV_PROC*,
CHAR*);
#ifdef __cplusplus
extern "C"
{
#endif
SRVRETCODE __declspec(dllexport)
xp_helloworld(SRV_PROC* pSrvProc);
#ifdef
__cplusplus
}
#endif
SRVRETCODE xp_helloworld(SRV_PROC*
pSrvProc)
{
char szText[13] = "Hello World!";
BYTE
bType;
ULONG cbMaxLen;
ULONG cbActualLen;
BOOL fNull;
/*
Определение количества переданных в расширенную хранимую
процедуру
параметров */
if (srv_rpcparams(pSrvProc) != 1)
{
printError(pSrvProc, "Не верное количество параметров!");
return
(XP_ERROR);
}
/* Получение информации о типе данных и длине
переданых параметров */
if (srv_paraminfo(pSrvProc, 1, &bType,
&cbMaxLen,
&cbActualLen, NULL, &fNull) ==
FAIL)
{
printError (pSrvProc,
"Не удаётся получить информацию о
входных параметрах ...");
return (XP_ERROR);
}
/* Проверяем,
является ли переданный параметр OUTPUT параметром */
if
((srv_paramstatus(pSrvProc, 1) & SRV_PARAMRETURN) ==
FAIL)
{
printError (pSrvProc,
"Переданный параметр не является
OUTPUT параметром!");
return (XP_ERROR);
}
/* Проверяем тип
данных переданного параметра */
if (bType != SRVBIGVARCHAR &&
bType != SRVBIGCHAR)
{
printError (pSrvProc, "Не верный тип
переданного параметра!");
return (XP_ERROR);
}
/* Убедимся,
что переданный параметр имеет достаточную длину для сохранения
возвращаемой строки */
if (cbMaxLen <
strlen(szText))
{
printError (pSrvProc,
"Передан параметр не
достаточной длины для сохранения n возвращаемой строки!");
return
(XP_ERROR);
}
/* Устаналиваем значение OUTPUT параметра
*/
if (FAIL == srv_paramsetoutput(pSrvProc, 1, (BYTE*)szText, 13,
FALSE))
{
printError (pSrvProc,
"Не могу установить значение
OUTPUT параметра...");
return (XP_ERROR);
}
srv_senddone(pSrvProc, (SRV_DONE_COUNT | SRV_DONE_MORE), 0,
1);
return (XP_NOERROR);
}
void printError (SRV_PROC
*pSrvProc, CHAR* szErrorMsg)
{
srv_sendmsg(pSrvProc, SRV_MSG_ERROR,
XP_HELLO_ERROR, SRV_INFO, 1,
NULL, 0, 0,
szErrorMsg,SRV_NULLTERM);
srv_senddone(pSrvProc, (SRV_DONE_ERROR |
SRV_DONE_MORE), 0, 0);
}
Не рассмотренными остались функции
srv_sendmsg и srv_senddone. Функция srv_sendmsg используется для посылки
сообщений клиенту. Вот её прототип:
int srv_sendmsg
(
SRV_PROC * srvproc,
int msgtype,
DBINT msgnum,
DBTINYINT
class,
DBTINYINT state,
DBCHAR * rpcname,
int rpcnamelen,
DBUSMALLINT linenum,
DBCHAR * message,
int
msglen
);
msgtype – определяет тип посылаемого
клиенту сообщения. Константа SRV_MSG_INFO обозначает информационное
сообщение, а SRV_MSG_ERROR сообщение об ошибке;
msgnum – номер
сообщения;
class - степень «тяжести» возникшей ошибки.
Информационные сообщения имеют значение степени «тяжести» меньшее или
равное 10;
state – номер состояния ошибки для текущего
сообщения. Этот параметр предоставляет информацию о контексте возникшей
ошибки. Допустимые значения лежат в диапазоне от 0 до 127;
rpcname – в
настоящее время не используется;
rpcnamelen - в настоящее время не
используется;
linenum – здесь можно указать номер строки
исходного кода. По этому значению, в последствие будет легко установить в
каком месте возникла ошибка. Если Вы не хотите использовать эту
возможность, тогда установите linenum в 0;
message – указатель на
строку посылаемую клиенту;
msglen – определяет длину в байтах
строки сообщения. Если это строка заканчивается нулевым символом, то
значение этого параметра можно установить равным
SRV_NULLTERM.
Возвращаемыме значения:
- в случае успеха
SUCCEED
- при неудаче FAIL.
В процессе работы расширенная
хранимая процедура должна регулярно сообщать клиентскому приложению свой
статус, т.е. посылать сообщения о выполненных действиях. Для этого и
предназначена функция srv_senddone:
int srv_senddone
(
SRV_PROC * srvproc,
DBUSMALLINT status,
DBUSMALLINT info,
DBINT count
);
status – статус флаг. Значение этого
параметра можно задавать использую логические операторы AND и OR для
комбинирования констант приведённых в таблице:
Status flag
Описание
SRV_DONE_FINAL Текущий набор результатов является
окончательным;
SRV_DONE_MORE Текущий набор результатов не является
окончательным – следует ожидать очердную порцию данных;
SRV_DONE_COUNT
Параметр count содержит верное значение
SRV_DONE_ERROR Используется для
уведомления о возникновении ошибок и немедленном
завершении.
into – зарезервирован, необходимо установить в
0.
count – количество результирующих наборов данных посылаемых клиенту.
Если флаг status установлен в SRV_DONE_COUNT, то count должен содержать
правильное количество посылаемый клиенту наборв записей.
Возвращаемыме
значения:
- в случае успеха SUCCEED
- при неудаче
FAIL.
Установка расширенных хранимых процедур на MS SQL Server
2000
1. Скопируйте dll библиотеку с расширенной хранимой процедурой
в каталог binn на машине с установленным MS SQL Server. У меня этот путь
следующий: C:Program FilesMicrosoft SQL ServerMSSQLBinn;
2.
Зарегистрирйте расширенную хранимую процедуру на серверt выполнив
следующий скрипт:
USE Master
EXECUTE SP_ADDEXTENDEDPROC
‘xp_helloworld’, ‘xp_helloworld.dll’
Протестируйте работу
xp_helloworld, выполнив такой скрипт:
DECLARE @Param
varchar(33)
EXECUTE xp_helloworld @Param OUTPUT
SELECT @Param AS
OUTPUT_Param
Заключение
На этом первая часть моей статьи
закончена. Теперь я уверен – Вы готовы справиться с нашим техническим
заданием на все 100%. В следующей статье Вы узнаете:
- Типы данных
определённые в ODS API;
- Особенности отладки расширенных хранимых
процдур;
- Как формировать recordset-ы и передавать их клиентскому
приложению;
- Чстично мы рассмотрим функции Active Directory Network
Manegment API необходимые для получения списка доменных
пользователей;
- Создадим готовый проект (реализуем наше техническое
задание)
Надеюсь - до скорой встречи!
PS: файлы примера для
статьи качать здесьдля студии
7.0
Версия для студии VC 6.0 здесь
Тип данных определённый в ODS API |
Тип данных в MS SQL Server 2000 |
Описание |
SRVBIGBINARY |
binary |
Бинарные данные. Максимальная размер 8000 байт. |
SRVBIGCHAR |
char |
Строка символов. Максимальный размер 8000 байт. |
SRVBIGVARBINARY |
varbinary |
Бинарные данные с переменным размером. 0 – 8000 байт. |
SRVBIGVARCHAR |
varchar |
Строка символов с переменным размером 0 – 8000 байт. |
SRVBINARY |
binary |
Бинарный тип данных |
SRVBIT |
Bit |
Бит |
SRVBITN |
bit null |
Бит разрешающие хранение значения NULL. |
SRVCHAR |
char |
Строка символов. Максимальный размер 8000 байт. |
SRVDATETIME |
datetime |
Тип данных для хранения значения даты/времени в 8 байтовом
формате. |
SRVDATETIM4 |
smalldatetime |
Тип данных для хранения значения даты/времени в 4 байтовом
формате. |
SRVDATETIMN |
datetime null |
smalldatetime или datetime тип данных разрешающий хранение значения
NULL. |
SRVDECIMAL |
decimal |
Десятичные числа в диапазоне 0 – 99. Размер 2 – 17 байт (в зависимости
от количества цифр). |
SRVDECIMALN |
decimal null |
Десятичные числа в диапазоне 0 – 99. Разрешает хранение значения
NULL. |
SRVFLT4 |
real |
Десятичные числа в диапазоне -3,40Е+38 – 3,40Е+38. Размер 4
байта. |
SRVFLT8 |
float |
Десятичные числа в диапазоне -1,79Е+308 – 1,79Е+308. . Размер 4 или 8
байт (в зависимости от величины мантиссы). |
SRVFLTN |
real | float null |
real или float тип данных разрешающий хранение значения NULL. |
SRVIMAGE |
image |
Бинарные данные. Максимальный размер 2Гб. |
SRVINT1 |
tinyint |
Целые числа в диапазоне 0 – 255. Размер 1 байт. |
SRVINT2 |
smallint |
Целые числа в диапазоне -32768 – 32767. Размер 2 байта. |
SRVINT4 |
Int |
Целые числа в диапазоне -2147483648 – 2147483647. Размер 4
байта. |
SRVINTN |
tinyint | smallint | int null |
tinyint, smallint, или int тип данных разрешающий хранения значения
NULL. |
SRVMONEY4 |
smallmoney |
Денежный тип данных. Обеспечивает хранение до 4-ёх цифр после
десятичной точки. Диапазон значений: -214748,3648 - +214748,3647. Размер 4
байта. |
SRVMONEY |
money |
Денежный тип данных. Обеспечивает хранение до 4-ёх цифр после
десятичной точки. Диапазон значений:-922337203685477,5808 -
+922337203685477,5807.Размер 8 байт. |
SRVMONEYN |
money | smallmoney null |
smallmoney или money разрешающий хранение значения NULL. |
SRVNCHAR |
nchar |
Строка символов в формате UNICODE. Размер 8000 байт (4000
символов). |
SRVNTEXT |
ntext |
Обеспечивает хранение текстовых блоков данных в формате UNICODE длиной
до 1073741823 символов. |
SRVNUMERIC |
numeric |
Десятичные числа в диапазоне 0 – 99. Размер 2 – 17 байт (в зависимости
от количества цифр). |
SRVNUMERICN |
numeric null |
numeric тип данных разрешающий хранение значения NULL. |
SRVNVARCHAR |
nvarchar |
Строка символов переменной длины в формате UNICODE. Максимальный
размер 8000 байт (4000 символов). |
SRVTEXT |
text |
Обеспечивает хранение текстовых блоков данных длиной до 2147483647
символов. |
SRVVARCHAR |
varchar |
Строка символов переменной длины. Размер 0 – 8000
байт. |